package com.zzyl.serve.service.impl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.serve.domain.DeviceData;
import com.zzyl.system.mapper.SysUserRoleMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.serve.mapper.AlertRuleMapper;
import com.zzyl.serve.domain.AlertRule;
import com.zzyl.serve.service.IAlertRuleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 报警规则Service业务层处理
 * 
 * @author zengxze
 * @date 2025-08-26
 */
@Service
public class AlertRuleServiceImpl extends ServiceImpl<AlertRuleMapper, AlertRule> implements IAlertRuleService
{
    @Autowired
    private AlertRuleMapper alertRuleMapper;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private SysUserRoleMapper userRoleMapper;

    /**
     * 查询报警规则
     * 
     * @param id 报警规则主键
     * @return 报警规则
     */
    @Override
    public AlertRule selectAlertRuleById(Long id)
    {
        return alertRuleMapper.selectById(id);
    }

    /**
     * 查询报警规则列表
     * 
     * @param alertRule 报警规则
     * @return 报警规则
     */
    @Override
    public List<AlertRule> selectAlertRuleList(AlertRule alertRule)
    {
        return alertRuleMapper.selectAlertRuleList(alertRule);
    }

    /**
     * 新增报警规则
     * 
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int insertAlertRule(AlertRule alertRule)
    {
        return alertRuleMapper.insert(alertRule);
    }

    /**
     * 修改报警规则
     * 
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int updateAlertRule(AlertRule alertRule)
    {
        return alertRuleMapper.updateById(alertRule);
    }

    /**
     * 批量删除报警规则
     * 
     * @param ids 需要删除的报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleByIds(Long[] ids)
    {
        return alertRuleMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除报警规则信息
     * 
     * @param id 报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleById(Long id)
    {
        return alertRuleMapper.deleteById(id);
    }


    @Override
    public void handleAlertJob() {
//        1.判断已启用的报警规则是否为空
        long l = count(Wrappers.<AlertRule>lambdaQuery().eq(AlertRule::getStatus, 1));
        if (l == 0){
            return;
        }

//        2.获取设备上报的设备
        List<Object> values = redisTemplate.opsForHash().values(CacheConstants.IOT_DEVICE_LAST_DATA);
        if (ObjectUtil.isEmpty(values)){
            return;
        }

//        3.循环遍历redis上获取的数据,得到每个设备的数据
        for (Object value : values) {
//            将数据转化成数组格式
            List<DeviceData> dataList = JSONUtil.toList(value.toString(), DeviceData.class);
//            遍历得到每个设备数据
            for (DeviceData deviceData : dataList) {
                handleDeviceData(deviceData);
            }
        }
    }

    /**
     * 判断报警是否触发
     * @param deviceData 每个设备的物模型数据
     */
    private void handleDeviceData(DeviceData deviceData) {
//        1.判断这条设备数据是否过去一分钟了,有就直接结束
        LocalDateTime alarmTime = deviceData.getAlarmTime();
        long between = LocalDateTimeUtil.between(alarmTime, LocalDateTime.now(), ChronoUnit.SECONDS);
        if (between>60){
            return;
        }

//        2.查询能够针对此规则生效的报警规则
        LambdaQueryWrapper<AlertRule> wrapper = Wrappers.<AlertRule>lambdaQuery()
                .eq(AlertRule::getStatus, 1)
                .eq(AlertRule::getProductKey, deviceData.getProductKey())
                .eq(AlertRule::getFunctionId, deviceData.getFunctionId())
                .in(AlertRule::getIotId, "-1", deviceData.getIotId());
        List<AlertRule> alertRuleList = list(wrapper);
        if (ObjectUtil.isEmpty(alertRuleList)){
            return;
        }

//        3.遍历每个规则: 判断当前这条设备 对 每条规则是否触发警报
        for (AlertRule alertRule : alertRuleList) {
            handleDeviceDataAlertRule(deviceData,alertRule);
        }

    }

    /**
     * 判断当前设备对每条规则是否触发警报
     * @param deviceData 要判断的设备数据
     * @param alertRule 要匹配的规则
     */
    private void handleDeviceDataAlertRule(DeviceData deviceData, AlertRule alertRule) {
//        1.判断这条设备数据,是否在规则的生效范围内
        String alertEffectivePeriod = alertRule.getAlertEffectivePeriod();
//        切分字符串alertEffectivePeriod从"~"里切开成两个, 并转化为时间
        String[] split = alertEffectivePeriod.split("~");
        LocalTime start = LocalTime.parse(split[0]);
        LocalTime end = LocalTime.parse(split[1]);

        LocalTime localTime = deviceData.getAlarmTime().toLocalTime();
//        判断是否在规则生效范围内
        if (localTime.isBefore(start) || localTime.isAfter(end)){
            return;
        }

//        2.判断设备数据有没有异常,没有直接结束
//         判断数据超过阈值
        double dataValue = Double.parseDouble(deviceData.getDataValue());
//        生成记录异常次数的key
        String contKey = StringUtils.format(CacheConstants.IOT_ALERT_COUNT_KEY, deviceData.getIotId(), alertRule.getId());
        if (("<".equals(alertRule.getOperator()) && dataValue>=alertRule.getValue())
             || (">=".equals(alertRule.getOperator()) && dataValue< alertRule.getValue())){
//            处理异常次数 ,清除掉积累的异常次数
            redisTemplate.delete(contKey);
            return;
        }

//        3.判断设备数据有没有达到报警阈值,没有直接结束
//        判断此时是否在沉默周期
        String format = StringUtils.format(CacheConstants.IOT_ALERT_SILENT_KEY, deviceData.getIotId(), alertRule.getId());
        Boolean hasKey = redisTemplate.hasKey(format);
        if (hasKey){
            return;
        }

//        判断上报数据次数是否达到周期阈值
        Long count = redisTemplate.opsForValue().increment(contKey, 1);
        if (count < alertRule.getDuration()){
            return;
        }

//        4.查找责任人,保存报警数据
//        清除上报次数
        redisTemplate.delete(contKey);
//        设置沉默标记
        redisTemplate.opsForValue().set(format,"1",alertRule.getAlertSilentPeriod(), TimeUnit.MINUTES);

//        根据报错原因查找责任人
        if(alertRule.getAlertDataType() ==1){
            Set<Long> userId =  userRoleMapper.selectUserIdByRuleName("维修工");
        }
//        todo
    }
}
